import threading
import time
from typing import Optional

try:
    from voice_module.voice_interface import VoiceInterface
    from voice_module.core.audio_queue_manager import AudioPriority
except ImportError:
    VoiceInterface = None
    AudioPriority = None


class IntegratedVoiceAssistantService:
    def __init__(self, command_executor):
        self.command_executor = command_executor
        self.voice: Optional[VoiceInterface] = getattr(command_executor, 'voice_interface', None)
        self.is_running = False
        self.wake_thread = None
        self.backend_processing = False
        self.interrupt_event = threading.Event()
        self.llm_thread = None
        self.SPEAKABLE_KEYS = [
            'tts_text', 'speech', 'assistant_reply', 'reply',
            'final_answer', 'text', 'answer', 'say'
        ]

    def _is_audio_playing(self) -> bool:
        try:
            aqm = getattr(self.voice, 'audio_queue_manager', None)
            player = getattr(self.voice, 'audio_player', None)
            if aqm and getattr(aqm, 'is_playing', False):
                return True
            if player and getattr(player, 'is_playing', False):
                return True
        except Exception:
            pass
        return False

    def start(self) -> bool:
        if not self.voice:
            return False
        if self.is_running:
            return True
        self.is_running = True
        try:
            self.voice.start_wake_detection()
        except Exception:
            pass
        self.wake_thread = threading.Thread(target=self._wake_loop, daemon=True)
        self.wake_thread.start()
        return True

    def stop(self) -> bool:
        self.is_running = False
        try:
            if self.voice:
                self.voice.stop_wake_detection()
        except Exception:
            pass
        try:
            if self.voice:
                self.voice.stop_audio(force=True)
        except Exception:
            pass
        try:
            if self.voice:
                self.voice.stop_recording()
        except Exception:
            pass
        return True

    def _wake_loop(self):
        while self.is_running:
            try:
                success, _, detected = self.voice.is_wake_detected()
                if success and detected:
                    if self.backend_processing or self._is_audio_playing():
                        self.handle_interrupt()
                    try:
                        self.voice.play_system_sound('sentence_i_am_here', blocking=True)
                    except Exception:
                        pass
                    self._single_interaction()
                time.sleep(0.1)
            except Exception:
                time.sleep(0.2)

    def _single_interaction(self):
        try:
            try:
                self.voice.play_system_sound('alert_start_records', blocking=True)
            except Exception:
                pass
            success, _, _ = self.voice.start_single_segment_recording(
                base_filename=f"assistant_{int(time.time())}"
            )
            if not success:
                try:
                    self.voice.play_system_sound('error')
                except Exception:
                    pass
                return
            while True:
                s, _, rec = self.voice.is_recording()
                if not s or not rec:
                    break
                time.sleep(0.1)
            success_stop, _, result_file = self.voice.stop_recording()
            if success_stop and result_file:
                try:
                    self.voice.play_system_sound('alert_stop_record')
                except Exception:
                    pass
                if hasattr(self.voice, 'stt_client') and self.voice.stt_client:
                    success_rec, _, text = self.voice.recognize_audio_file(result_file)
                    if success_rec and text and text.strip():
                        try:
                            self.voice.play_system_sound('success')
                        except Exception:
                            pass
                        self._start_backend_processing(text)
                    else:
                        try:
                            self.voice.play_system_sound('sentence_pardon')
                        except Exception:
                            pass
            else:
                try:
                    self.voice.play_system_sound('error')
                except Exception:
                    pass
        except Exception:
            pass

    def _start_backend_processing(self, text: str):
        try:
            self.backend_processing = True
            self.interrupt_event.clear()
            self.llm_thread = threading.Thread(target=self._backend_worker, args=(text,), daemon=True)
            self.llm_thread.start()
        except Exception:
            self.backend_processing = False

    def _backend_worker(self, text: str):
        response_text = ''
        try:
            if self.interrupt_event.is_set():
                return
            response_dict = self.command_executor.run_text_workflow(text)
            if isinstance(response_dict, dict):
                response_text = self._extract_speakable_text(response_dict)
        finally:
            if self.interrupt_event.is_set():
                self.backend_processing = False
                return
            if response_text:
                self._speak_response(response_text)
            self.backend_processing = False

    def _speak_response(self, text: str):
        try:
            self.voice.play_synthesized_speech(
                text,
                volume=None,
                priority=AudioPriority.NORMAL,
                use_queue=True
            )
        except Exception:
            pass

    def handle_interrupt(self):
        try:
            self.interrupt_event.set()
            try:
                self.command_executor.request_cancel()
            except Exception:
                pass
            try:
                self.voice.stop_audio(force=True)
            except Exception:
                pass
            try:
                self.voice.interrupt_audio_playback()
            except Exception:
                pass
            try:
                self.voice.stop_recording()
            except Exception:
                pass
            self.backend_processing = False
        except Exception:
            pass

    def _extract_speakable_text(self, response_dict) -> str:
        try:
            data_obj = response_dict.get('data', {}) if isinstance(response_dict, dict) else {}
            outputs = data_obj.get('outputs', {}) if isinstance(data_obj, dict) else {}
            if isinstance(outputs, dict):
                for k in self.SPEAKABLE_KEYS:
                    val = outputs.get(k)
                    if isinstance(val, str) and val.strip():
                        return val.strip()
        except Exception:
            pass
        return ''
